﻿// ------------------------------------------------------------------------------------
//      Copyright (c) 2013 uhavemyword@gmail.com. All rights reserved.
//      Created by Ben at 01/04/2013 14:34:04
// ------------------------------------------------------------------------------------

namespace CP.General
{
    using System;
    using System.Configuration;
    using System.Text;

    public static class Utility
    {
        private static Random _random = new Random();

        public static string GetRandomString(int length)
        {
            string chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
            StringBuilder builder = new StringBuilder(length);
            for (int i = 0; i < length; i++)
            {
                builder.Append(chars[_random.Next(chars.Length)]);
            }
            return builder.ToString();
        }

        /// <summary>
        /// Encrypt/Decrypt connectionStrings section of app.config/web.config, and save the file.
        /// </summary>
        /// <remarks>
        /// <see cref="http://www.codeproject.com/Tips/598863/EncryptionplusDecryptionplusConnectionplusStringpl"/>
        /// </remarks>
        public static void EncryptConnectionString(bool encrypt, string exeFilePath)
        {
            Configuration configuration = null;

            // Open the configuration file and retrieve the connectionStrings section.
            configuration = ConfigurationManager.OpenExeConfiguration(exeFilePath);
            ConnectionStringsSection configSection = configuration.GetSection("connectionStrings") as ConnectionStringsSection;
            if (!configSection.ElementInformation.IsLocked && !configSection.SectionInformation.IsLocked)
            {
                if (encrypt && !configSection.SectionInformation.IsProtected)
                {
                    //this line will encrypt the file
                    configSection.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
                }

                //encrypt is true so encrypt
                if (!encrypt && configSection.SectionInformation.IsProtected)
                {
                    //this line will decrypt the file. 
                    configSection.SectionInformation.UnprotectSection();
                }

                //re-save the configuration file section
                configSection.SectionInformation.ForceSave = true;

                // Save the current configuration
                configuration.Save();
            }
        }

        #region Retry
        /// <summary>
        /// Re-try logic to suppress the exception thrown by the Operation for times.
        /// The Operation will be excuted maxRetries times at most.
        /// </summary>
        public static void RetryAction(Action action, int maxRetries = 2, int retryInterval = 500)
        {
            for (int i = 1; i <= maxRetries; i++)
            {
                try
                {
                    action();
                    break;
                }
                catch
                {
                    if (i >= maxRetries)
                    {
                        throw;
                    }
                    else
                    {
                        System.Threading.Thread.Sleep(retryInterval);
                    }
                }
            }
        }

        /// <summary>
        /// Re-try logic to suppress the exception thrown by the Operation for times.
        /// The Operation will be excuted maxRetries times at most.
        /// </summary>
        public static TResult RetryFunc<TResult>(Func<TResult> func, int maxRetries = 2, int retryInterval = 500)
        {
            TResult result = default(TResult);

            for (int i = 1; i <= maxRetries; i++)
            {
                try
                {
                    result = func();
                    break;
                }
                catch
                {
                    if (i >= maxRetries)
                    {
                        throw;
                    }
                    else
                    {
                        System.Threading.Thread.Sleep(retryInterval);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// Re-try logic to suppress the exception thrown by the Operation for times.
        /// The Operation will be excuted maxRetries times at most.
        /// </summary>
        public static TResult RetryFunc<T, TResult>(Func<T, TResult> func, T arg, int maxRetries = 2, int retryInterval = 500)
        {
            TResult result = default(TResult);

            for (int i = 1; i <= maxRetries; i++)
            {
                try
                {
                    result = func(arg);
                    break;
                }
                catch
                {
                    if (i >= maxRetries)
                    {
                        throw;
                    }
                    else
                    {
                        System.Threading.Thread.Sleep(retryInterval);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// Re-try logic to suppress the exception thrown by the Operation for times.
        /// The Operation will be excuted maxRetries times at most.
        /// </summary>
        public static TResult RetryFunc<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2, int maxRetries = 2, int retryInterval = 500)
        {
            TResult result = default(TResult);

            for (int i = 1; i <= maxRetries; i++)
            {
                try
                {
                    result = func(arg1, arg2);
                    break;
                }
                catch
                {
                    if (i >= maxRetries)
                    {
                        throw;
                    }
                    else
                    {
                        System.Threading.Thread.Sleep(retryInterval);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// Re-try logic to suppress the exception thrown by the Operation for times.
        /// The Operation will be excuted maxRetries times at most.
        /// </summary>
        public static TResult RetryFunc<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3, int maxRetries = 2, int retryInterval = 500)
        {
            TResult result = default(TResult);

            for (int i = 1; i <= maxRetries; i++)
            {
                try
                {
                    result = func(arg1, arg2, arg3);
                    break;
                }
                catch
                {
                    if (i >= maxRetries)
                    {
                        throw;
                    }
                    else
                    {
                        System.Threading.Thread.Sleep(retryInterval);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// Re-try logic to suppress the exception thrown by the Operation for times.
        /// The Operation will be excuted maxRetries times at most.
        /// </summary>
        public static TResult RetryFunc<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4, int maxRetries = 2, int retryInterval = 500)
        {
            TResult result = default(TResult);

            for (int i = 1; i <= maxRetries; i++)
            {
                try
                {
                    result = func(arg1, arg2, arg3, arg4);
                    break;
                }
                catch
                {
                    if (i >= maxRetries)
                    {
                        throw;
                    }
                    else
                    {
                        System.Threading.Thread.Sleep(retryInterval);
                    }
                }
            }

            return result;
        }
        #endregion
    }
}
